package latestrpmimpl

import (
	"bytes"
	"encoding/base64"
	"encoding/csv"
	"errors"
	"fmt"
	"io"
	"strings"
	"time"

	"github.com/astaxie/beego"
	"github.com/opensourceways/robot-gitee-lib/client"
	"github.com/opensourceways/server-common-lib/utils"
	"github.com/sirupsen/logrus"
)

const (
	retryTimes = 3
)

type PkgRPM struct {
	Org        string
	Repo       string
	Branch     string
	PathPrefix string
}

func NewLatestRpm() *latestRpm {
	token := beego.AppConfig.String("gitee::git_token")
	cli := client.NewClient(func() []byte {
		return []byte(token)
	})

	rpm := PkgRPM{
		Org:        "openeuler_latest_rpms",
		Repo:       "obs_pkg_rpms_20231109",
		Branch:     "master",
		PathPrefix: "latest_rpm/",
	}

	return &latestRpm{
		rpm:        rpm,
		cli:        cli,
		buildTime:  make(map[string]map[string]time.Time),
		httpClient: utils.NewHttpClient(retryTimes),
	}
}

type latestRpm struct {
	rpm        PkgRPM
	cli        client.Client
	buildTime  map[string]map[string]time.Time
	httpClient utils.HttpClient
}

func (l *latestRpm) InitData(branches []string) error {
	for _, branch := range branches {
		content, err := l.getContent(branch)
		if err != nil {
			continue
		}

		l.buildTime[branch] = l.parseFile(content)
	}

	return nil
}

func (l *latestRpm) getContent(branch string) ([]byte, error) {
	path := fmt.Sprintf("%s%s.csv", l.rpm.PathPrefix, branch)
	content, err := l.cli.GetPathContent(l.rpm.Org, l.rpm.Repo, path, l.rpm.Branch)
	if err != nil {
		logrus.Errorf("get latest rpms of %s from gitee failed: %s", branch, err.Error())
		return nil, err
	}

	return base64.StdEncoding.DecodeString(content.Content)
}

func (l *latestRpm) parseFile(content []byte) map[string]time.Time {
	buff := bytes.NewBuffer(content)
	r := csv.NewReader(buff)

	const lineLength = 3
	componentAndTime := make(map[string]time.Time)
	for {
		line, err1 := r.Read()
		if err1 == io.EOF {
			break
		}

		if err1 != nil {
			logrus.Errorf("new-cold-patch-cve-collect parse line error:%s", err1.Error())
		}

		if len(line) < lineLength {
			continue
		}

		split := strings.Fields(line[2])
		if len(split) == 0 {
			continue
		}

		t, err1 := time.ParseInLocation("20060102 15-04-05", line[0], time.Local)
		if err1 != nil {
			continue
		}

		componentAndTime[line[1]] = t
	}

	return componentAndTime
}

func (l *latestRpm) GetBuildTime(branch, component string) (time.Time, error) {
	componentMap, ok := l.buildTime[branch]
	if !ok {
		return time.Time{}, errors.New("branch not exists")
	}

	t, ok := componentMap[component]
	if !ok {
		return time.Time{}, errors.New("component not exists")
	}

	return t, nil
}
